package service

import (
	"fmt"
	"sync"
	"time"
)

// Snowflake 雪花算法实现
type Snowflake struct {
	mu            sync.Mutex // 互斥锁（保障并发安全）
	lastTimestamp int64      // 上次ID生成时间戳（毫秒级）
	workerId      int        // 工作节点ID（当前固定为0）
	sequence      int        // 序列计数器（0-4095）
}

func NewSnowflake() *Snowflake {
	return &Snowflake{
		lastTimestamp: -1,
		workerId:      0, // TODO: 增加 WorkID 参数
		sequence:      0,
	}
}

// Next 生成一个新的唯一ID
func (s *Snowflake) Next(raw bool) (string, error) {
	s.mu.Lock()
	defer s.mu.Unlock()

	timestamp := time.Now().UnixNano() / 1000000 // 转换为毫秒
	if timestamp < s.lastTimestamp {
		return "", fmt.Errorf("时钟向后移动。在 %d 毫秒内拒绝生成id", s.lastTimestamp-timestamp)
	}
	// 序列号管理
	if timestamp == s.lastTimestamp {
		// 位运算优化
		s.sequence = (s.sequence + 1) & 4095
		// 当前毫秒序列号耗尽
		if s.sequence == 0 {
			// 阻塞到下一毫秒
			timestamp = s.waitNextMillis()
		}
	} else {
		// 新时间戳重置序列号
		s.sequence = 0
	}
	s.lastTimestamp = timestamp
	// ID构造
	id := (timestamp << 22) | (int64(s.workerId) << 10) | int64(s.sequence)
	if raw {
		// 原始数字格式
		return fmt.Sprintf("%d", id), nil
	}
	// 带日期前缀的增强格式（如202504291234567890）
	now := time.Now()
	return fmt.Sprintf("%d%02d%02d%d", now.Year(), now.Month(), now.Day(), id), nil
}

// waitNextMillis 该方法用于在雪花算法中解决同一毫秒内序列号耗尽时的时间窗口阻塞问题，通过自旋等待（忙等待）强制推进时间戳到下一毫秒，
// 确保生成的 ID 在时间维度上严格递增且唯一。
func (s *Snowflake) waitNextMillis() int64 {
	// 当前毫秒时间戳
	timestamp := time.Now().UnixNano() / 1000000
	// 自旋等待直到新时间窗口
	for timestamp <= s.lastTimestamp {
		timestamp = time.Now().UnixNano() / 1000000
	}
	return timestamp
}
